<?php

/**
 * Sqlite3 backend for the phpCacheTag library
 *
 * @package phpCacheTag
 * @author maxvodo
 * @version 0.1
 */
class SqlitecacheTag extends CacheTag
{

  /**
   *
   * @var SQLiteDatabase
   */
  private $_db;

  const C_MAXROWS = 120;
  const C_ERASEROWS = 40;
  const C_FILENAME = 'cache.db';

  /**
   *
   *
   * @return boolean
   */
  public function __construct()
  {
    if (!class_exists('SQLite3')) {
      throw new Exception('SQLite is not installed');
    }

    $this->_db = new SQLite3(self::C_FILENAME, SQLITE3_OPEN_CREATE | SQLITE3_OPEN_READWRITE);

    if (is_null($this->_db))
      throw new Exception('Cant open SQLite database!');

    //table exist?
    $sqlResult = $this->_db->query('SELECT * FROM tblCache WHERE 1<>1');

    if ($sqlResult === false) {
      //not exist
      //create structure
      $this->_db->exec('CREATE TABLE tblCache (key STRING(255) PRIMARY KEY, value TEXT, created TIMESTAMP, ttl INTEGER)');
    }

    //Parent constructor has to be called
    parent::__construct();

    return true;
  }

  public function __destruct()
  {
    $this->_db->close();
  }

  /**
   * Returns value of the variable in cache
   *
   * @param string $name
   * @return mixed
   */
  public function Get($name)
  {
    $sqlResult = $this->_db->query('SELECT value, (created + ttl) as good FROM tblCache WHERE key = \'' . $name . '\'');

    if ($sqlResult !== false) {
      $result = $sqlResult->fetchArray();

      if ($result['good'] >= time()) {
        return unserialize(stripslashes($result['value']));
      }
    }

    return false;
  }

  /**
   * Replaces a value of the variable by name
   *
   * @param string $name
   * @param mixed $value
   * @return mixed
   */
  protected function Replace($name, $value)
  {
    $this->_db->exec('UPDATE tblCache SET value = \'' . addslashes(serialize($value)) . '\' WHERE key = \'' . $name . '\'');
    return (bool) $this->_db->changes();
  }

  /**
   * Deletes variable in cache
   *
   * @param	string	$name
   * @return boolean
   */
  protected function Delete($name)
  {
    $this->_db->exec('DELETE FROM tblCache WHERE key = \'' . $name . '\'');
    return (bool) $this->_db->changes();
  }

  /**
   * Adds/replaces variable in cache
   *
   * @param	string	$varName
   * @param	mixed	$value
   * @param	int $timeoutMinutes 	minutes to store data
   * @return mixed
   */
  public function Set($varName, $value, $timeoutMinutes = 0)
  {
    $this->_db->exec('DELETE FROM tblCache WHERE key = \'' . $varName . '\'');
    $this->_db->exec('INSERT INTO tblCache (key, value, created, ttl) VALUES ('
            . "'" . $varName . "', "
            . "'" . addslashes(serialize($value)) . "', "
            . "'" . time() . "', "
            . "'" . $timeoutMinutes * 60 . "'"
            . ')'
    );

    if (rand(0, 31) == 13) {
      //time to check size
      $sqlResult = $this->_db->query('SELECT COUNT(*) as size FROM tblCache');
      $result = $sqlResult->fetchArray();

      if ($result['size'] > self::C_MAXROWS) {
        //need crop size
        $sqlResult = $this->_db->query('SELECT key FROM tblCache ORDER BY created asc LIMIT ' . self::C_ERASEROWS);
        $result = $sqlResult->fetchArray();

        $strDelete = '(' . implode(',', $result) . ')';
        $this->_db->exec('DELETE FROM tblCache WHERE key IN ' . $strDelete);
      }
    }

    return (bool) $this->_db->lastInsertRowID();
  }

}
